#!/usr/bin/perl
# forked from the cygwin.com upset cvs version
# cgf: "I'm not interested in turning it into a general purpose tool and I'm not
#      interested in bug reports, patches, augmentations, etc."
#      http://cygwin.com/ml/cygwin-apps/2004-10/msg00560.html

=pod

=head1 NAME 

upset - update local setup.ini
mksetup - maintain /usr/src/setup/setup.ini and local packages

=head1 DESCRIPTION

upset is together with the Cygwin::Setup perl module a general purpose package and
setup.ini maintenance tool for Cygwin package writers, to avoid
packaging and other setup errors beforehand.

upset will create a setup.ini file from the parsed packages in the given 
subdirs, and warn on any syntax error, wrong category or unresolved dependency.
mksetup is used to locally test packages before uploading.

upset and the Cygwin perl modules are based on the cygwin-internal 
upset version by Christopher Faylor. They will be regularly sync'ed with 
the cygwin CVS version, but are independent.

=head1 SYNOPSIS

Move your setup.hint, binary and src tar.bz2 into the correct 
setup/release/<package> subdir.

upset --extnowarn -C -u setup.ini release contrib

mksetup 

  update the local setup.ini and warn about syntax errors
  or missing dependencies.

mksetup setup 

  run setup.exe with your local repository added.
  So you can test the package before requesting a upload.

mksetup up

  upload all changed files to publicly accessable server.

=head1 OPTIONS

=over

=item B<-u setup.ini>

Update an existing setup.ini file. setup.ini or setup or setup.bz2
If no -u otion is given, setup.ini is written to stdout.

=item B<--[no]setup-version>

On --nosetup-version no setup.exe is searched in the current path to
determine the setup.exe version.

=item B<-C>

Compress the setup.ini file to setup.bz2

=item --extnowarn|-e

Don't warn about unresolved dependencies on locally installed packages.

=head1 INSTALL

  fix some options at the head of /usr/sbin/mksetup

  cd /usr/src
  mkdir setup; cd setup

  # put your unmaintained contrib packages here
  mkdir -p contrib

  # put your maintained release packages here
  mkdir -p release

  # symlink setup.exe into the current dir
  ln -s <path>/setup.exe setup.exe

=head1 AUTHORS

  Christopher Faylor
  Reini Urban
  Yaakov Selkowitz

=head1 COPYRIGHT AND DISCLAIMER

  Copyright 2002, 2003 by Red Hat, Inc.
  Copyright 2004 by Reini Urban.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

If you do not have a copy of the GNU General Public License write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
MA 02139, USA.

=cut

use strict;
my ($u, $pgm, $compress);

use Getopt::Long;

$pgm = readlink $0;
$pgm and $0 = $pgm;
$pgm = ($0 =~ m!/([^/]+)$!)[0] || $0;
my $setup_version = 1;
my $extnowarn = 0;
GetOptions('u=s'=>\$u, 'setup-version!'=>\$setup_version, 'C'=>\$compress, 'extnowarn|e!'=>\$extnowarn) or do {
    die "usage: $pgm [-u setup-file] [--[no]setup-version] [dir]\n";
};

use FindBin;
use lib "$FindBin::Bin";

use Cygwin::Setup;
use Cygwin::Setup::Listing;
use Cygwin::Setup::ByDir;

my ($initfn, $newfn);
open(STDOUT, ">" . ($newfn = "/tmp/upset.$$")) if $u;
$| = 1;

my $package = new Cygwin::Setup;
my $extpackage = {};

$. = 0;
if ($u && open(U, '<', $u)) {
    $initfn = $u;
    if ($u =~ /.bz2$/) {
        $initfn =~ s/\.bz2$//;
        if (system "bunzip2 $u") {
	    $u = $initfn;
	    open(U, '<', $u);
        }
    }
    while ($package->iniparse ($u, \*U)) {
	next;
    }
}

if ($package->{-error}) {
    print STDERR "upset: $package->{-error}\n";
    exit 1;
}

if ($setup_version) {
    $package->exe_version("setup.exe") or die "couldn't get version from setup.exe - $!\n";
}

if ($package->{-error}) {
    print STDERR "upset: $package->{-error}\n";
    exit 1;
}

@ARGV = ('release') unless @ARGV;
$package->dir_update(@ARGV);

if ($package->{-error}) {
    print STDERR "upset: $package->{-error}\n";
    exit 1;
}

# prevent from warning refers to non-existant package x
open I, "< /etc/setup/installed.db";
while (<I>) {
    m/^(\S+)\s(\S+)\s/;
    $extpackage->{$1} = $2;
}
close I;

print <<BLAH;
# This file is automatically generated.  If you edit it, your
# edits will be discarded next time the file is generated.
# See http://cygwin.com/setup.html for details.
#
BLAH

# Also updates auto dependencies

$package->update_listing();

my $pkg = $package->{'__setup'}{''};
print "setup-timestamp: ", time, "\n";
print "setup-version: ", $pkg->{'setup-version'}, "\n"
    if $pkg->{'setup-version'};

delete $package->{'__setup'};

for my $p ($package->names) {
    next if defined($package->{$p}{''}{'skip'});
    if ($package->{$p}{_me} ne $p) {
	$p = $package->{$p}{_me};
	next if $package->{$p}{''}{'skip'};
    }

    $pkg = $package->{$p};
    my $pkgbase = $pkg->{''};
    $pkgbase->{'skip'} = 1;
    print "\n@ $p\n";
    if ($pkgbase->{'sdesc'}) {
	$pkgbase->{'sdesc'} =~ s/^("?)[^:]+:\s*/$1/o;
	$pkgbase->{'sdesc'} =~ s/^("?)([a-z])/$1\u$2/o;
	print "sdesc: ", $pkgbase->{'sdesc'}, "\n";
	# delete $pkgbase->{'sdesc'};
    }
    if ($pkgbase->{'ldesc'}) {
	print "ldesc: ", $pkgbase->{'ldesc'}, "\n";
	delete $pkgbase->{'ldesc'};
    }
    if ($pkgbase->{'category'}) {
        for my $cat (split(' ', $pkgbase->{'category'})) {
            die "invalid category $cat in $p\n" 
	      unless $cat =~ /^(?:@{[join('|' => @Cygwin::Setup::categories)]})$/;
        }
	print "category:", map(" \u$_", (split(' ', $pkgbase->{'category'}))), "\n";
	delete $pkgbase->{'category'};
    } else {
	print "category: ", 'Misc', "\n";
    }
    # keys which take multiple packages (only partial setup.exe support yet)
    foreach my $key (@Cygwin::Setup::pkgkeys) {
      if ($pkgbase->{$key}) {
	foreach my $r (split(' ', $pkgbase->{$key})) {
	    if (!defined($package->{$r})) {
		if (defined($extpackage->{$r})) {
		    warn "upset: * warning package $p $key external package $r\n" unless $extnowarn;
		} else {
		    warn "upset: *** warning package $p $key non-existent package $r\n" ;
		}
	    }
	}
	print $key, ": ", $pkgbase->{$key}, "\n";
	delete $pkgbase->{$key};
      }
    }
    # other new keys
    foreach my $key (@Cygwin::Setup::otherkeys) {
      if ($pkgbase->{$key}) {
	print $key, ": ", $pkgbase->{$key}, "\n";
	delete $pkgbase->{$key};
      }
    }
    for my $g ('', 'prev', 'test') {
	my $ver = $pkg->{$g} or next;
	print "[$g]\n" if length($g);
	yup: for my $n ('version', 'install', 'source') {
	    if ($ver->{$n}) {
		print "$n: $ver->{$n}\n";
		next;
	    } elsif ($n ne 'source' || !defined($pkg->{''}{'external-source'})) {
		next;
	    }

	    my $v = $ver->{'version'};
	    defined($v) or next;

	    my $tarpkg = $package->{$pkg->{''}{'external-source'}};
	    my $srcfn = $tarpkg->{_me} . '-' . $v . '-src.tar.bz2';
	    my $srcpath = $package->{-sources}{$srcfn};
	    if (defined($srcpath)) {
		print "$n: $srcpath\n";
	     } else {
		 for my $g1 ('', 'prev', 'test') {
		     if ($tarpkg->{$g1}{'version'} eq $v) {
			 if (!$tarpkg->{$g1}{'source'}) {
			     warn "upset: *** No source file found for $pkg->{''}{'external-source'}-$v\n";
			     next;
			 } else {
			     print "$n: $tarpkg->{$g1}{'source'}\n";
			 }
			next yup;
		     }
		 }
		warn "upset: *** warning package $p refers to non-existent external-source: $pkg->{''}{'external-source'}\n";
	    }
	}
    }
}

if ($u) {
    my $changed = 0;
    die "Couldnt open $u" unless $initfn;
    close(U);
    open(STDOUT, ">/dev/null");
    system  qw/diff -I^setup-timestamp -w -B -q/, $initfn, $newfn and do {
	system 'mv', $newfn, $initfn;
	$changed = 1;
    };
    if ($compress) {
        my $bz2 = $initfn;
        $bz2 =~ s/\.ini//o;
        $bz2 .= '.bz2';
        exec "exec bzip2 <$initfn >$bz2" if $changed || ! -f $bz2;
    }
    unlink($newfn);
}
exit(0);

### Setup "cgf" style for perl-mode and cperl-mode.
## Local Variables:
## perl-indent-level: 4
## perl-continued-statement-offset: 4
## perl-continued-brace-offset: 0
## perl-brace-offset: 0
## perl-brace-imaginary-offset: 0
## perl-label-offset: -4
## cperl-indent-level: 4
## cperl-brace-offset: 0
## cperl-continued-brace-offset: 0
## cperl-label-offset: -4
## cperl-extra-newline-before-brace: t
## cperl-merge-trailing-else: nil
## cperl-continued-statement-offset: 4
## End:
